using System;
using System.Threading.Tasks;
using Essensoft.Paylink.WeChatPay;
using Essensoft.Paylink.WeChatPay.V3;
using Essensoft.Paylink.WeChatPay.V3.Domain;
using Essensoft.Paylink.WeChatPay.V3.Request;
using Microsoft.Extensions.DependencyInjection;
using XUCore.Ddd.Domain;
using XUCore.Extensions;
using XUCore.NetCore;

namespace XUCore.WeChat
{
    public class WeChatPayService
    {
        private readonly IWeChatPayClient client;
        private readonly WeChatFuncs weChatFuncs;
        public WeChatPayService(IServiceProvider serviceProvider)
        {
            this.client = serviceProvider.GetRequiredService<IWeChatPayClient>();
            this.weChatFuncs = serviceProvider.GetRequiredService<WeChatFuncs>();
        }
        /// <summary>
        /// 获取支付签名，发起支付，微信公众号或者小程序的微信支付订单（app == PublicAccount 或者 空 为公众号）
        /// </summary>
        /// <param name="weChatType">微信类型</param>
        /// <param name="app">应用标识</param>
        /// <param name="option"></param>
        /// <returns></returns>
        public async Task<WeChatPayDictionary> PaySignAsync(WeChatType weChatType, string app, Action<WeChatPayTransactionsJsApiBodyModel> option)
        {
            var wechatPayOptions = default(WeChatPayOptions);

            if (weChatType == WeChatType.PublicAccount)
                wechatPayOptions = weChatFuncs.GetWeChatOptions(app)?.WeChatPayOptions;
            else
                wechatPayOptions = weChatFuncs.GetMiniProgramOptions(app)?.WeChatPayOptions;

            if (wechatPayOptions == null)
                throw new WeChatSdkException($"{nameof(WeChatPayService)}，App:{app}，获取微信支付配置失败。");

            var model = new WeChatPayTransactionsJsApiBodyModel
            {
                AppId = wechatPayOptions.AppId,
                MchId = wechatPayOptions.MchId,
                //Amount = new Amount { Total = orderModel.Total, Currency = "CNY" },
                //Description = orderModel.Description,
                //NotifyUrl = orderModel.NotifyUrl,
                //OutTradeNo = orderModel.OutTradeNo,
                //Payer = new PayerInfo { OpenId = OpenId }
            };

            option(model);

            var request = new WeChatPayTransactionsJsApiRequest();

            request.SetBodyModel(model);

            var response = await client.ExecuteAsync(request, wechatPayOptions);

            if (response.IsError)
                Failure.Error(response.Body);

            if (response.StatusCode == System.Net.HttpStatusCode.OK)
            {
                var req = new WeChatPayJsApiSdkRequest
                {
                    Package = "prepay_id=" + response.PrepayId
                };

                return await client.ExecuteAsync(req, wechatPayOptions);
            }

            // 将参数(parameter)给 小程序端
            // https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_5_4.shtml

            return new WeChatPayDictionary();
        }
        /// <summary>
        /// 发起退款，微信公众号或者小程序的微信支付订单（app == PublicAccount 或者 空 为公众号）
        /// </summary>
        /// <param name="weChatType">微信类型</param>
        /// <param name="app">应用标识</param>
        /// <param name="outTradeNo"></param>
        /// <param name="option"></param>
        /// <returns></returns>
        public async Task<Result> RefundAsync(WeChatType weChatType, string app, string outTradeNo, Action<WeChatPayRefundDomesticRefundsBodyModel> option)
        {
            var wechatPayOptions = default(WeChatPayOptions);

            if (weChatType == WeChatType.PublicAccount)
                wechatPayOptions = weChatFuncs.GetWeChatOptions(app)?.WeChatPayOptions;
            else
                wechatPayOptions = weChatFuncs.GetMiniProgramOptions(app)?.WeChatPayOptions;

            if (wechatPayOptions == null)
                throw new WeChatSdkException($"{nameof(WeChatPayService)}，App:{app}，获取微信支付配置失败。");

            //获取微信交易订单信息
            var tranRequest = new WeChatPayTransactionsOutTradeNoRequest
            {
                OutTradeNo = outTradeNo,
            };

            tranRequest.SetQueryModel(new WeChatPayTransactionsOutTradeNoQueryModel
            {
                MchId = wechatPayOptions.MchId,
            });

            var tranResponse = await client.ExecuteAsync(tranRequest, wechatPayOptions);
            // 交易状态，枚举值： SUCCESS：支付成功 REFUND：转入退款 NOTPAY：未支付 CLOSED：已关闭 REVOKED：已撤销（付款码支付） USERPAYING：用户支付中（付款码支付）
            // PAYERROR：支付失败(其他原因，如银行返回失败) ACCEPT：已接收，等待扣款
            // 示例值：SUCCESS
            switch (tranResponse.TradeState)
            {
                case "SUCCESS":
                    {
                        //发起退款
                        var model = new WeChatPayRefundDomesticRefundsBodyModel()
                        {
                            TransactionId = tranResponse.TransactionId,
                            //OutTradeNo = order.OrderNumber,
                            //OutRefundNo = $"R{order.OrderNumber}",
                            //NotifyUrl = $"{GlobalStatic.RootUrl}/Pay/ProductNotify/Refund?app=",
                            Amount = new RefundAmount
                            {
                                Refund = (int)tranResponse.Amount.PayerTotal,
                                Total = (int)tranResponse.Amount.Total,
                                Currency = tranResponse.Amount.PayerCurrency
                            }
                        };

                        option(model);

                        //发起退款
                        var request = new WeChatPayRefundDomesticRefundsRequest();
                        request.SetBodyModel(model);

                        var response = await client.ExecuteAsync(request, wechatPayOptions);

                        // 退款到银行发现用户的卡作废或者冻结了，导致原路退款银行卡失败，可前往商户平台-交易中心，手动处理此笔退款。 
                        // 枚举值： SUCCESS：退款成功 CLOSED：退款关闭 PROCESSING：退款处理中 ABNORMAL：退款异常
                        // 示例值：SUCCESS
                        switch (response.Status)
                        {
                            case "SUCCESS": //退款成功
                                return new Result(StateCode.Success, subCode: "SUCCESS", message: "退款成功", data: "SUCCESS");
                            case "CLOSED": //退关关闭
                                return new Result(StateCode.Success, subCode: "CLOSED", message: "退关关闭", data: "CLOSED");
                            case "PROCESSING": //退款处理中
                                return new Result(StateCode.Success, subCode: "PROCESSING", message: "退款处理中，请稍等", data: "PROCESSING");
                            case "ABNORMAL": //退款异常
                                return new Result(StateCode.Success, subCode: "ABNORMAL", message: "退款异常", data: "ABNORMAL");
                            default:
                                return new Result(StateCode.Success, subCode: "", message: "退款操作异常", data: "");
                        }
                    }
                case "REFUND": //转入退款
                    return new Result(StateCode.Success, subCode: "REFUND", message: "正在转入退款，请稍等", data: "");
                case "NOTPAY": //未支付
                    return new Result(StateCode.Success, subCode: "", message: "没有支付，无法退款", data: "");
                case "CLOSED": //已关闭
                    return new Result(StateCode.Success, subCode: "", message: "支付已关闭，无法退款", data: "");
                case "REVOKED": //已撤销（付款码支付）
                    return new Result(StateCode.Success, subCode: "", message: "已撤销支付，无法退款", data: "");
                case "USERPAYING": //用户支付中（付款码支付）
                    return new Result(StateCode.Success, subCode: "", message: "用户支付中，无法退款", data: "");
                case "PAYERROR": //支付失败(其他原因，如银行返回失败)
                    return new Result(StateCode.Success, subCode: "", message: "支付失败，无法退款", data: "");
                case "ACCEPT": //已接收，等待扣款
                    return new Result(StateCode.Success, subCode: "", message: "已接收，等待扣款", data: "");
                default:
                    return new Result(StateCode.Success, subCode: "", message: "交易订单操作异常", data: "");
            }
        }
        /// <summary>
        /// 取消微信公众号或者小程序的微信支付订单（app == PublicAccount 或者 空 为公众号）
        /// </summary>
        /// <param name="weChatType">微信类型</param>
        /// <param name="app">应用标识</param>
        /// <param name="outTradeNo"></param>
        /// <returns></returns>
        public async Task<Result> CancelAsync(WeChatType weChatType, string app, string outTradeNo)
        {
            var wechatPayOptions = default(WeChatPayOptions);

            if (weChatType == WeChatType.PublicAccount)
                wechatPayOptions = weChatFuncs.GetWeChatOptions(app)?.WeChatPayOptions;
            else
                wechatPayOptions = weChatFuncs.GetMiniProgramOptions(app)?.WeChatPayOptions;

            if (wechatPayOptions == null)
                throw new WeChatSdkException($"{nameof(WeChatPayService)}，App:{app}，获取微信支付配置失败。");

            var model = new WeChatPayTransactionsOutTradeNoCloseBodyModel
            {
                MchId = wechatPayOptions.MchId,
            };

            var request = new WeChatPayTransactionsOutTradeNoCloseRequest
            {
                OutTradeNo = outTradeNo,
            };

            request.SetBodyModel(model);

            await client.ExecuteAsync(request, wechatPayOptions);

            return new Result(StateCode.Success, subCode: "", message: "取消成功", data: 1);
        }
    }
}